Measure a tmux socket path where tmux resolves it - #730
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## fix/723-repr-socket-dir #730 +/- ##
===========================================================
+ Coverage 52.40% 52.63% +0.22%
===========================================================
Files 26 26
Lines 3742 3764 +22
Branches 747 747
===========================================================
+ Hits 1961 1981 +20
- Misses 1477 1481 +4
+ Partials 304 302 -2 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Code reviewFound 1 issue:
Lines 227 to 240 in f3771f7 Reproduced on this head, with $ TMUX_TMPDIR=$LONG tmux -f /dev/null display-message -p '#{socket_path}'
/tmp/sd3394337/tmux-1000/defaulttmux
The 🤖 Generated with Claude Code - If this code review was useful, please react with 👍. Otherwise, react with 👎. |
8f437fa to
1bd85e1
Compare
bd730e5 to
593d5ff
Compare
|
Force-pushed a redesign of where the check runs. The earlier revision validated the socket path in tmux reads A bare client prefers
This also closes the design question raised in review: |
593d5ff to
337c921
Compare
Code reviewFound 1 issue, now fixed in 337c921:
Reproduced deterministically on that revision: the test passes, then Fixed by scoping the patches to the assertions with Also corrected in the same push: 🤖 Generated with Claude Code - If this code review was useful, please react with 👍. Otherwise, react with 👎. |
c8356b9 to
66ff46f
Compare
Code reviewFound 3 issues, all fixed in 66ff46f:
Measured:
🤖 Generated with Claude Code - If this code review was useful, please react with 👍. Otherwise, react with 👎. |
4ad7f9c to
57d931d
Compare
Code reviewFound 2 issues, fixed in 57d931d:
Both now create the directory first, so the resolved path is one tmux would really bind.
🤖 Generated with Claude Code - If this code review was useful, please react with 👍. Otherwise, react with 👎. |
57d931d to
adcc295
Compare
Code reviewFound 2 issues, fixed in adcc295:
🤖 Generated with Claude Code - If this code review was useful, please react with 👍. Otherwise, react with 👎. |
1bd85e1 to
d368b44
Compare
e07a79f to
c24f1b3
Compare
d368b44 to
77971b6
Compare
c24f1b3 to
1ffaa55
Compare
77971b6 to
6ca471e
Compare
why: A tmux socket is a UNIX domain socket, so its path is capped by `sockaddr_un` -- 107 bytes on Linux, 103 on macOS. tmux reports an overrun as `error connecting to <path> (File name too long)`, which names the path but not how far over it is, nor which variable made it that long. The overrun is usually inherited rather than typed: a deep pytest `tmp_path`, an XDG runtime dir, a nested worktree. what: - Add `exc.SocketPathTooLong` carrying the path, the byte count, how far over the limit it is, and the environment variable it came from. - Measure each route where tmux itself resolves it. A `socket_path` is passed through unchanged as `-S<path>`, so it is settled at construction and refused there. A `socket_name` resolves against `$TMUX_TMPDIR`, which tmux re-reads at exec rather than when the Server was built, so measuring it at construction would check a value with no bearing on what tmux binds -- it is measured per command instead, where `colors` is already checked. - Add `Server.socket_args()` and build every tmux spawn from it. The flags were previously reconstructed in four places -- `cmd`, `raise_if_dead`, the format-query layer and the control-mode client, the last two spawning tmux themselves -- so a check on any one of them would have covered part of the surface. - Resolve a bare server's socket the way a bare tmux client does, preferring `$TMUX` over `$TMUX_TMPDIR`. Inside a pane tmux never consults the directory, so measuring it would refuse a server tmux reaches without difficulty. - Constructing a named or bare Server has no side effect, so `is_alive()` still answers for a server that cannot be reached, and `raise_if_dead()` still reports why. Fixes #725
why: A pytest tmp_path is nested deep by design, so a socket under it can overrun what a UNIX socket address holds. The failure arrived as a tmux error attributed to whichever command ran first. what: - Document the limit and the short-socket-directory workaround on the pytest-plugin usage page. - Say on the configuration page that libtmux reads $TMUX_TMPDIR to know where the socket lands, and that a deep one raises SocketPathTooLong.
why: A socket path that cannot bind fails as a tmux error naming the path but not the numbers, and a deep pytest `tmp_path` reaches the limit without anyone typing a long path. what: - Record the socket-path measurement under `What's new`, naming where each route is measured and the shorter-directory workaround.
1ffaa55 to
b11c74f
Compare
Fixes #725. Stacked on #727.
A tmux socket is a UNIX domain socket, so its path is capped by
sockaddr_un— 107 bytes on Linux, 103 on macOS. Over that, tmux says:That names the path, but not how far over the limit it is, nor which variable made it that long. This adds
exc.SocketPathTooLongcarrying all three.Where the measurement happens
The routes are not equivalent, so they are not measured in the same place.
socket_path=is handed to tmux unchanged as-S<path>. Nothing can revise it, so it is measured at construction, where the caller still holds the frame that wrote it.socket_name=is not. libtmux passes-L<name>and tmux resolves the directory from$TMUX_TMPDIRwhen it runs. Measured on tmux 3.7b: construct aServer(socket_name=…)withTMUX_TMPDIR=a, change it tob, then dispatch — tmux binds underb. So a construction-time check on that route tests a value with no bearing on what tmux will use. It passes when the variable later grows (hitting the exactFile name too longthis exists to prevent) and refuses when it later shrinks. Those paths are measured per command, at the same pointcolorsis already validated.A bare
Server()inside a tmux pane is left alone entirely. A bare tmux client prefers$TMUXover$TMUX_TMPDIR, so a deep socket directory is irrelevant to it — measured: with$TMUXset,tmux list-sessionssucceeds while$TMUX_TMPDIRnames a directory far too deep to bind. Checking it would have refused a server tmux reaches without difficulty, in the case libtmux is most often used from.Server.socket_args()The
-S/-Lflags were being reconstructed in four places —Server.cmd(),Server.raise_if_dead(), the format-query layer, and the control-mode client, the last two spawning tmux through their ownPopen/check_call. A check added to any one of them would have covered part of the dispatch surface. They now all build their argv fromServer.socket_args(), so the measurement is total by construction rather than by discipline.Constructing a server has no side effect
Naming a server is not using one. A named or bare
Serveralways builds, soServer.is_alive()keeps answering for a server that cannot be reached — an address the kernel cannot hold is one more way of not being alive — andServer.raise_if_dead()keeps being the way to ask why.Server.sessionsstays lenient and returns an emptyQueryList, matching the documented contract for list accessors.Verification
ruff check,ruff format,mypy(69 files),py.test --reruns 0(1477 passed, 1 skipped),just build-docs— all clean. Green on tmux 3.2a through master.